import React, {FC, useCallback, useEffect, useImperativeHandle, useMemo, useRef} from "react";
import {Transfer} from "antd";
import {getObjByRule, isArray, isObject} from "../../utils";
import useStateRef from "../../customUse/useStateRef.tsx";
import {AxiosGet} from "../../services/HttpService.tsx";

interface SelectTransferProps {
    init?: any,
    onChange?: Function,
    value?: string,
    joinKey?: string,
    ds?: any,
    url?: string,
    dataSource?: any[],
    params?: any,
    format?: any,
    transferField?: string[],
    width?: number,
    height?: number,
    titles?: any[]
}

const SelectTransfer: FC<SelectTransferProps> = (props) => {
    const {
        joinKey = ",",
        width = 250,
        height = 300,
        titles = [],
        format = {
            key: "id",
            label: "zhCn|usEn|ptBr"
        }
    } = props;

    const dataMapRef = useRef({}),
        dataRef = useRef([]),
        targetKeysRef = useRef([]),
        leftSelectKeysRef = useRef([]),
        rightSelectKeysRef = useRef([]);

    const [data, setData] = useStateRef([], dataRef),
        [targetKeys, setTargetKeys] = useStateRef([], targetKeysRef);

    const getValue = useCallback(() => {
        const {ds = {}} = props;
        let newValue = ds.value || props.value;
        if (newValue) {
            newValue = newValue.split(joinKey);
        }
        return newValue || []
    }, [props.ds, props.value]);

    const loadData = useCallback(async () => {
        const {url, params, dataSource, transferField = ["alternativeRoles", "containRoles"]} = props;
        let res, options = [], selectKeys = getValue();
        if (dataSource) {
            res = dataSource
        } else if (url) {
            const {data} = await AxiosGet(url, {
                ...params
            });
            res = data
        }
        if (isArray(res)) {
            options = res;
        } else if (isObject(res)) {
            const [leftKey, rightKey] = transferField
            let leftData = res[leftKey], rightData = res[rightKey];
            options = [...leftData, ...rightData]
            selectKeys = [...new Set([...selectKeys, ...rightData.map(i => i[format.value])])];
        }
        // 去重并且格式化按照指定格式，格式化数据
        const dataMap = new Map();
        options.forEach(item => {
            dataMap.set(item[format.key], getObjByRule(item, format, true));
        });
        options = Array.from(dataMap.values());
        dataMapRef.current = dataMap
        setData(options)
        setTargetKeys(selectKeys)
    }, [props.transferField, props.url, props.params, props.dataSource, props.value, props.ds, props.format]);

    useEffect(() => {
        loadData()
    }, [props.dataSource, props.url, props.params]);

    useImperativeHandle(props.init, () => {
        return {
            getSelectRows: () => {
                return targetKeysRef.current.map(k => {
                    if (dataMapRef.current.get(k)) {
                        return dataMapRef.current.get(k);
                    }
                    return null
                }).filter(i => i);
            },
            getLeftSelectRows: () => {
                return leftSelectKeysRef.current.map(k => {
                    if (dataMapRef.current.get(k)) {
                        return dataMapRef.current.get(k);
                    }
                    return null
                }).filter(i => i);
            },
            getRightSelectRows: () => {
                return rightSelectKeysRef.current.map(k => {
                    if (dataMapRef.current.get(k)) {
                        return dataMapRef.current.get(k);
                    }
                    return null
                }).filter(i => i);
            },
            addRightRows: (rows = [], ids = []) => {
                let newData = [...dataRef.current];
                rows.forEach(i => {
                    let index = newData.findIndex(l => (l.contactId === i.contactId))
                    if (index === -1) {
                        let node = getObjByRule(i, format, true);
                        newData.push(node)
                    }
                });
                setData(newData)
                const currentKeysSet = new Set(targetKeysRef.current);
                ids.forEach(id => currentKeysSet.add(id));
                const newTargetKeys = Array.from(currentKeysSet);
                setTargetKeys(newTargetKeys);
            }
        }
    });

    const handleChange = useCallback((selectKyes) => {
        setTargetKeys(selectKyes)
        props.onChange && props.onChange(selectKyes.join(joinKey))
    }, [props.onChange]);

    const handleSelectChange = useCallback((leftSelectKeys, rightSelectKeys) => {
        leftSelectKeysRef.current = leftSelectKeys;
        rightSelectKeysRef.current = rightSelectKeys;
    }, [])

    const handleSearch = useCallback((inputValue, option) => {
        return option.label.indexOf(inputValue) !== -1;
    }, []);

    const renderSelectTransfer = useMemo(() => {
        if (!data) {
            return
        }
        return (
            <div className="sf_core_select_transfer">
                <Transfer
                    listStyle={{
                        width: width,
                        height: height,
                    }}
                    titles={titles}
                    showSearch
                    dataSource={data}
                    targetKeys={targetKeys}
                    onChange={handleChange}
                    onSelectChange={handleSelectChange}
                    filterOption={handleSearch}
                    pagination
                    render={(item) => item.label}
                />
            </div>
        )
    }, [data, targetKeys]);

    return (renderSelectTransfer);
};

export default React.memo(SelectTransfer);